/*
 * Copyright (c) 2021 柯华栋
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ipc_data.h"

// 导入锁函数
void ipc_lock(void);
void ipc_unlock(void);

#define IPC_MAP_ITEM_TYPE_U8			0
#define IPC_MAP_ITEM_TYPE_S16			1
#define IPC_MAP_ITEM_TYPE_S32   		2
#define IPC_MAP_ITEM_TYPE_S64   		3
#define IPC_MAP_ITEM_TYPE_FLOAT   		4
#define IPC_MAP_ITEM_TYPE_DOUBLE   		5
#define IPC_MAP_ITEM_TYPE_STRING   		6

// 数组
#define IPC_MAP_ITEM_TYPE_U8_ARRAY    	7		// 字节数组(CarPlay视频流需要用到)
#define IPC_MAP_ITEM_TYPE_S16_ARRAY   	8
#define IPC_MAP_ITEM_TYPE_S32_ARRAY   	9
#define IPC_MAP_ITEM_TYPE_S64_ARRAY  	10
#define IPC_MAP_ITEM_TYPE_FLOAT_ARRAY 	11
#define IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY	12
#define IPC_MAP_ITEM_TYPE_STRING_ARRAY	13

struct _ipc_u8_array_t {
	int 		ref_cnt;			// 计数
	int 		size;				// 数组条目数量
	uint8_t	 	value[0];			// 数组生命周期和 ipc_u8_array_t 绑定
};

struct _ipc_s16_array_t {
	int 		ref_cnt;			// 计数
	int 		size;				// 数组条目数量
	int16_t	 	value[0];			// 数组生命周期和 ipc_s16_array_t 绑定
};

struct _ipc_s32_array_t {
	int  		ref_cnt;			// 计数
	int  		size;				// 数组条目数量
	int32_t 	value[0];			// 数组生命周期和 ipc_s32_array_t 绑定
};

struct _ipc_s64_array_t {
	int  		ref_cnt;			// 计数
	int  		size;				// 数组条目数量
	int64_t  	value[0];			// 数组生命周期和 ipc_s64_array_t 绑定
};

struct _ipc_float_array_t {
	int  		ref_cnt;			// 计数
	int  		size;				// 数组条目数量
	float  		value[0];			// 数组生命周期和 ipc_float_array_t 绑定
};

struct _ipc_double_array_t {
	int  		ref_cnt;			// 计数
	int 		size;				// 数组条目数量
	double  	value[0];			// 数组生命周期和 ipc_double_array_t 绑定
};

struct _ipc_string_array_t {
	int  		ref_cnt;			// 计数
	int 		size;				// 数组条目数量
	gchar* 		value[0];			// 数组和数组条目生命周期都和ipc_string_array_t绑定
};

typedef struct
{
	int				type;		// 条目类型
	gchar*			key;		// 生命周期和ipc_map_item_t绑定

	union {
		uint8_t				u8_value;
		int16_t				s16_value;
		int32_t 			s32_value;
		int64_t				s64_value;
		float				float_value;
		double 				double_value;
		gchar*				string_value;	// 生命周期和ipc_map_item_t绑定,查询时返回的是g_str_dup
		ipc_u8_array_t*		u8_array;
		ipc_s16_array_t*	s16_array;
		ipc_s32_array_t*	s32_array;
		ipc_s64_array_t*	s64_array;
		ipc_float_array_t*	float_array;
		ipc_double_array_t*	double_array;
		ipc_string_array_t* string_array;
	} v;
} ipc_map_item_t;


// TODO. map的ref, unref函数
struct _ipc_map_t
{
	int 				ref_cnt;	// 计数
	int 				size;		// 条目数量
	int 				capacity;	// 条目容量
	ipc_map_item_t** 	items;		// 条目(插入时按二分查找插入进行排序,用于快速获取指定的键值对)
};

// dbuf辅助序列化 ------------------------------------------------------------------------

// https://gitee.com/mirrors/QuickJS/blob/master/cutils.h
// https://gitee.com/mirrors/QuickJS/blob/master/cutils.c

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);

typedef struct
{
    uint8_t* 	buf;
    size_t 		size;
    size_t allocated_size;
	int error; /* true if a memory allocation error occurred */
    DynBufReallocFunc *realloc_func;
    void *opaque; /* for realloc_func */
} DynBuf;

static void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)
{
    return realloc(ptr, size);
}

static void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)
{
    memset(s, 0, sizeof(*s));
    if (!realloc_func)
        realloc_func = dbuf_default_realloc;
    s->opaque = opaque;
    s->realloc_func = realloc_func;
}

static void dbuf_init(DynBuf *s)
{
    dbuf_init2(s, NULL, NULL);
}

/* return < 0 if error */
static int dbuf_realloc(DynBuf *s, size_t new_size)
{
    size_t size;
    uint8_t *new_buf;
    if (new_size > s->allocated_size) {
        if (s->error)
            return -1;
        size = s->allocated_size * 3 / 2;
        if (size > new_size)
            new_size = size;
        new_buf = s->realloc_func(s->opaque, s->buf, new_size);
        if (!new_buf) {
            s->error = TRUE;
            return -1;
        }
        s->buf = new_buf;
        s->allocated_size = new_size;
    }
    return 0;
}


static int dbuf_put(DynBuf *s, const uint8_t *data, size_t len)
{
    if (unlikely((s->size + len) > s->allocated_size)) {
        if (dbuf_realloc(s, s->size + len))
            return -1;
    }
    memcpy(s->buf + s->size, data, len);
    s->size += len;
    return 0;
}

static inline int dbuf_put_u8(DynBuf *s, uint8_t val)
{
    return dbuf_put(s, (uint8_t *)&val, 1);
}

static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
{
    return dbuf_put(s, (uint8_t *)&val, 2);
}

static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
{
    return dbuf_put(s, (uint8_t *)&val, 4);
}

static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
{
    return dbuf_put(s, (uint8_t *)&val, 8);
}

static inline int dbuf_put_float(DynBuf *s, float val)
{
	return dbuf_put(s, (uint8_t *)&val, 4);
}

static inline int dbuf_put_double(DynBuf *s, double val)
{
	return dbuf_put(s, (uint8_t *)&val, 8);
}



// 创建array(各项都是0) ----------------------------------------------------------
#define ipc_array_new(array_type, value_type, size)												\
	assert(size > 0);																				\
	array_type* array = (array_type*) malloc(sizeof(array_type) + sizeof(value_type) * size);		\
	array->ref_cnt = 1;																				\
	array->size = size;																				\
	memset(array->value, 0, sizeof(value_type) * size);												\
	return array;																					\

ipc_u8_array_t* 	ipc_u8_array_new(int size) 		{ipc_array_new(ipc_u8_array_t, uint8_t, size)}
ipc_s16_array_t* 	ipc_s16_array_new(int size)   	{ipc_array_new(ipc_s16_array_t, int16_t, size)}
ipc_s32_array_t* 	ipc_s32_array_new(int size)		{ipc_array_new(ipc_s32_array_t, int32_t, size)}
ipc_s64_array_t* 	ipc_s64_array_new(int size)		{ipc_array_new(ipc_s64_array_t, int64_t, size)}
ipc_float_array_t* 	ipc_float_array_new(int size)	{ipc_array_new(ipc_float_array_t, float, size)}
ipc_double_array_t* ipc_double_array_new(int size)	{ipc_array_new(ipc_double_array_t, double, size)}
ipc_string_array_t* ipc_string_array_new(int size)	{ipc_array_new(ipc_string_array_t, gchar*, size)}


// 创建array ---------------------------------------------------------------------
#define ipc_array_new2(array_type, value_type, value, size)											\
	assert(size > 0);																				\
	array_type* array = (array_type*) malloc(sizeof(array_type) + sizeof(value_type) * size);		\
	array->ref_cnt = 1;																				\
	array->size = size;																				\
	memcpy(array->value, value, sizeof(value_type) * size);											\
	return array;

ipc_u8_array_t* 	ipc_u8_array_new2(uint8_t* value, int size)		{ipc_array_new2(ipc_u8_array_t, uint8_t, value, size)}
ipc_s16_array_t* 	ipc_s16_array_new2(int16_t* value, int size)	{ipc_array_new2(ipc_s16_array_t, int16_t, value, size)}
ipc_s32_array_t* 	ipc_s32_array_new2(int32_t* value, int size)	{ipc_array_new2(ipc_s32_array_t, int32_t, value, size)}
ipc_s64_array_t* 	ipc_s64_array_new2(int64_t* value, int size)	{ipc_array_new2(ipc_s64_array_t, int64_t, value, size)}
ipc_float_array_t* 	ipc_float_array_new2(float* value, int size)	{ipc_array_new2(ipc_float_array_t, float, value, size)}
ipc_double_array_t* ipc_double_array_new2(double* value, int size)	{ipc_array_new2(ipc_double_array_t, double, value, size)}

ipc_string_array_t* ipc_string_array_new2(const gchar** value, int size)
{
	assert(size > 0);
	ipc_string_array_t* array = (ipc_string_array_t*) malloc(sizeof(ipc_string_array_t*) + sizeof(gchar*) * size);
	array->ref_cnt = 1;
	array->size = size;
	for (int i = 0; i < size; i++)
		array->value[i] = str_check_dup(value[i]);
	return array;
}


// 获取大小 ----------------------------------------------------------------------

#define ipc_array_size(array)		\
	assert(array);					\
	return array->size;				\

int ipc_u8_array_size(ipc_u8_array_t* array)		{ ipc_array_size(array) }
int ipc_s16_array_size(ipc_s16_array_t* array)		{ ipc_array_size(array) }
int ipc_s32_array_size(ipc_s32_array_t* array)		{ ipc_array_size(array) }
int ipc_s64_array_size(ipc_s64_array_t* array)		{ ipc_array_size(array) }
int ipc_float_array_size(ipc_float_array_t* array)	{ ipc_array_size(array) }
int ipc_double_array_size(ipc_double_array_t* array){ ipc_array_size(array) }
int ipc_string_array_size(ipc_string_array_t* array){ ipc_array_size(array) }

// 获取位置上的条目 ------------------------------------------------------------------

#define ipc_array_get(array, pos)		\
	assert(array);						\
	assert(pos>=0&&pos<array->size);	\
	return array->value[pos];			\


uint8_t ipc_u8_array_get(ipc_u8_array_t* array, int pos) 				{ipc_array_get(array, pos)}
int16_t ipc_s16_array_get(ipc_s16_array_t* array, int pos)				{ipc_array_get(array, pos)}
int32_t ipc_s32_array_get(ipc_s32_array_t* array, int pos)				{ipc_array_get(array, pos)}
int64_t ipc_s64_array_get(ipc_s64_array_t* array, int pos)				{ipc_array_get(array, pos)}
float   ipc_float_array_get(ipc_float_array_t* array, int pos)			{ipc_array_get(array, pos)}
double  ipc_double_array_get(ipc_double_array_t* array, int pos)		{ipc_array_get(array, pos)}
const gchar*  ipc_string_array_get(ipc_string_array_t* array, int pos)	{ipc_array_get(array, pos)}


// 设置位置上的条目 --------------------------------------------------------------

#define ipc_array_set(array, pos, value)	\
	assert(array);							\
	assert(pos>=0&&pos<array->size);		\
	array->value[pos] = value;				\

void ipc_u8_array_set(ipc_u8_array_t* array, int pos, uint8_t value)		{ipc_array_set(array, pos, value)}
void ipc_s16_array_set(ipc_s16_array_t* array, int pos, int16_t value)		{ipc_array_set(array, pos, value)}
void ipc_s32_array_set(ipc_s32_array_t* array, int pos, int32_t value)		{ipc_array_set(array, pos, value)}
void ipc_s64_array_set(ipc_s64_array_t* array, int pos, int64_t value)		{ipc_array_set(array, pos, value)}
void ipc_float_array_set(ipc_float_array_t* array, int pos, float value)	{ipc_array_set(array, pos, value)}
void ipc_double_array_set(ipc_double_array_t* array, int pos, double value) {ipc_array_set(array, pos, value)}

void ipc_string_array_set(ipc_string_array_t* array, int pos, const gchar* value)
{
	assert(array);
	assert(pos>=0&&pos<array->size);
	ipc_lock();
	str_check_free(array->value[pos]);
	array->value[pos] = str_check_dup(value);
	ipc_unlock();
}


// 引用相关 ----------------------------------------------------------------------

#define array_ref(array)				\
	if (array != NULL)					\
	{									\
		ipc_lock();						\
		assert(array->ref_cnt > 0);		\
		array->ref_cnt++;				\
		int cnt = array->ref_cnt;		\
		ipc_unlock();					\
		return cnt;						\
	}									\
	return 0;							\


#define array_unref(array)				\
	if (array != NULL)					\
	{									\
		ipc_lock();						\
		assert(array->ref_cnt > 0);		\
		array->ref_cnt--;				\
		if (array->ref_cnt == 0)		\
		{								\
			/* value在array内从块中 */  \
			free(array);				\
			ipc_unlock();				\
			return 0;					\
		}								\
		int cnt = array->ref_cnt;		\
		ipc_unlock();					\
		return cnt;						\
	}									\
	return 0;							\



// 添加引用
int ipc_u8_array_ref(ipc_u8_array_t* array) 			{array_ref(array)}


int ipc_s16_array_ref(ipc_s16_array_t* array) 			{array_ref(array)}
int ipc_s32_array_ref(ipc_s32_array_t* array) 			{array_ref(array)}
int ipc_s64_array_ref(ipc_s64_array_t* array) 			{array_ref(array)}
int ipc_float_array_ref(ipc_float_array_t* array) 		{array_ref(array)}
int ipc_double_array_ref(ipc_double_array_t* array) 	{array_ref(array)}
int ipc_string_array_ref(ipc_string_array_t* array) 	{array_ref(array)}

// 删除引用
int ipc_u8_array_unref(ipc_u8_array_t* array) 			{array_unref(array)}
int ipc_s16_array_unref(ipc_s16_array_t* array) 		{array_unref(array)}
int ipc_s32_array_unref(ipc_s32_array_t* array) 		{array_unref(array)}
int ipc_s64_array_unref(ipc_s64_array_t* array) 		{array_unref(array)}
int ipc_float_array_unref(ipc_float_array_t* array) 	{array_unref(array)}
int ipc_double_array_unref(ipc_double_array_t* array) 	{array_unref(array)}

int ipc_string_array_unref(ipc_string_array_t* array)
{
	if (array != NULL)
	{
		ipc_lock();
		assert(array->ref_cnt > 0);
		array->ref_cnt--;
		if (array->ref_cnt == 0) {
			for (int i = 0; i < array->size; i++) {
				str_check_free(array->value[i]);
			}
			/* value在array内从块中 */
			free(array);
			ipc_unlock();
			return 0;
		}
		int cnt = array->ref_cnt;
		ipc_unlock();
		return cnt;
	}
	return 0;
}

// 创建, 序列化, 反序列化 map -----------------------------------------------------

#define get_new_capcity_by_size(x) (((x) + 16) * 3 / 2)

/* 释放条目的值 */
static void ipc_map_item_free_value(ipc_map_item_t* item)
{
	switch (item->type)
	{
		case IPC_MAP_ITEM_TYPE_STRING:
			str_check_free(item->v.string_value);
			break;

		case IPC_MAP_ITEM_TYPE_U8_ARRAY:
			ipc_u8_array_unref(item->v.u8_array);
			break;

		case IPC_MAP_ITEM_TYPE_S16_ARRAY:
			ipc_s16_array_unref(item->v.s16_array);
			break;

		case IPC_MAP_ITEM_TYPE_S32_ARRAY:
			ipc_s32_array_unref(item->v.s32_array);
			break;

		case IPC_MAP_ITEM_TYPE_S64_ARRAY:
			ipc_s64_array_unref(item->v.s64_array);
			break;

		case IPC_MAP_ITEM_TYPE_FLOAT_ARRAY:
			ipc_float_array_unref(item->v.float_array);
			break;

		case IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY:
			ipc_double_array_unref(item->v.double_array);
			break;

		case IPC_MAP_ITEM_TYPE_STRING_ARRAY:
			ipc_string_array_unref(item->v.string_array);
			break;
	}
}


/* 释放条目空间 */
static void ipc_map_item_free(ipc_map_item_t* item)
{
	// 释放键
	str_check_free(item->key);
	// 释放值
	ipc_map_item_free_value(item);
	// 释放条目本身
	free(item);
}


/* 创建map */
ipc_map_t* ipc_map_new(void)
{
	ipc_map_t* map = (ipc_map_t*) malloc(sizeof(ipc_map_t));
	assert(map);
	map->ref_cnt = 1;
	map->size = 0;
	map->capacity = get_new_capcity_by_size(0);
	map->items = (ipc_map_item_t**) malloc(sizeof(ipc_map_item_t*) * map->capacity);
	return map;
}

ipc_string_array_t* ipc_map_keys(ipc_map_t* map)
{
	ipc_lock();
	if (map == NULL || map->size == 0)
		return NULL;
	ipc_string_array_t* array = ipc_string_array_new(map->size);
	for (int i = 0; i < map->size; i++)
		ipc_string_array_set(array, i, map->items[i]->key);
	ipc_unlock();
	return array;
}

int ipc_map_ref_cnt(ipc_map_t* map)
{
	return map == NULL ? 0 : map->ref_cnt;
}


/* 添加map引用 */
int ipc_map_ref(ipc_map_t* map)
{
	if (map != NULL)
	{
		ipc_lock();
		assert(map->ref_cnt > 0);
		map->ref_cnt++;
		int cnt = map->ref_cnt;
		ipc_unlock();
		return cnt;
	}
	return 0;
}


/* 解除map引用 */
int ipc_map_unref(ipc_map_t* map)
{
	if (map != NULL)
	{
		ipc_lock();
		assert(map->ref_cnt > 0);
		map->ref_cnt--;
		if (map->ref_cnt == 0) {
			// 释放全部item
			ipc_map_item_t** items = map->items;
			for (int i = 0; i < map->size; i++) {
				ipc_map_item_free(items[i]);
			}
			free(items);
			free(map);
			ipc_unlock();
			return 0;
		}
		int cnt = map->ref_cnt;
		ipc_unlock();
		return cnt;
	}
	return 0;
}

static void dbuf_put_ipc_str(DynBuf* s, const gchar* str)
{
	int len = str == NULL ? 0 : strlen(str);
	dbuf_put_u32(s, len);
	if (len != 0) {
		dbuf_put(s, (const uint8_t *)str, len);
	}
}

static void dbuf_put_ipc_map_item(DynBuf* s, ipc_map_item_t* item)
{
	// 添加键
	dbuf_put_ipc_str(s, item->key);

	// 添加类型
	dbuf_put_u8(s, item->type);

	// 添加值
	switch (item->type)
	{
		case IPC_MAP_ITEM_TYPE_U8:
			dbuf_put_u8(s, item->v.u8_value);
			break;

		case IPC_MAP_ITEM_TYPE_S16:
			dbuf_put_u16(s, item->v.s16_value);
			break;

		case IPC_MAP_ITEM_TYPE_S32:
			dbuf_put_u32(s, item->v.s32_value);
			break;

		case IPC_MAP_ITEM_TYPE_S64:
			dbuf_put_u64(s, item->v.s64_value);
			break;

		case IPC_MAP_ITEM_TYPE_FLOAT:
			dbuf_put_float(s, item->v.float_value);
			break;

		case IPC_MAP_ITEM_TYPE_DOUBLE:
			dbuf_put_double(s, item->v.double_value);
			break;

		case IPC_MAP_ITEM_TYPE_STRING:
			dbuf_put_ipc_str(s, item->v.string_value);
			break;

		case IPC_MAP_ITEM_TYPE_U8_ARRAY: {
			ipc_u8_array_t* array = item->v.u8_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, array->value, array->size);
			break;
		}

		case IPC_MAP_ITEM_TYPE_S16_ARRAY: {
			ipc_s16_array_t* array = item->v.s16_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, (const uint8_t *)&array->value[0], array->size*2);
			break;
		}

		case IPC_MAP_ITEM_TYPE_S32_ARRAY: {
			ipc_s32_array_t* array = item->v.s32_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, (const uint8_t *)&array->value[0], array->size*4);
			break;
		}

		case IPC_MAP_ITEM_TYPE_S64_ARRAY: {
			ipc_s64_array_t* array = item->v.s64_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, (const uint8_t *)&array->value[0], array->size*8);
			break;
		}

		case IPC_MAP_ITEM_TYPE_FLOAT_ARRAY: {
			ipc_float_array_t* array = item->v.float_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, (const uint8_t *)&array->value[0], array->size*4);
			break;
		}

		case IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY: {
			ipc_double_array_t* array = item->v.double_array;
			dbuf_put_u32(s, array->size);
			dbuf_put(s, (const uint8_t *)&array->value[0], array->size*8);
			break;
		}

		case IPC_MAP_ITEM_TYPE_STRING_ARRAY: {
			ipc_string_array_t* array = item->v.string_array;
			dbuf_put_u32(s, array->size);
			for (int i = 0; i < array->size; i++)
				dbuf_put_ipc_str(s, array->value[i]);
			break;
		}
	}
}


/** 序列化map(map保持不变) */
uint8_t* ipc_map_serial(ipc_map_t* map, int* size)
{
	ipc_lock();

	if (size == NULL || map == NULL || map->size == 0) {
		ipc_unlock();
		return NULL;
	}

	DynBuf buf;
	dbuf_init(&buf);

	for (int i = 0; i < map->size; i++)
		dbuf_put_ipc_map_item(&buf, map->items[i]);

	ipc_unlock();

	*size = buf.size;
	return buf.buf;
}

static void free_data_for_variant(gpointer data)
{
	free(data);
}

GVariant* ipc_map_to_variant(ipc_map_t* map)
{
	int size;
	uint8_t* data = ipc_map_serial(map, &size);
	return g_variant_new("(@ay)", g_variant_new_from_data(
		G_VARIANT_TYPE_BYTESTRING, data, size, TRUE, free_data_for_variant, data == NULL ? NULL : data));
}

ipc_map_t*  ipc_map_from_variant(GVariant* parameters)
{
	GVariant* data = NULL;
	g_variant_get(parameters, "(@ay)", &data);
	if (data == NULL)
	{
		return NULL;
	}
	return ipc_map_unserial(
		(uint8_t*)g_variant_get_data(data),
		g_variant_get_size(data)
	);
}

#define rbuf_get(rbuf, value, type, type_size)	\
	if (rbuf->off+type_size > rbuf->size)			\
		return -1;								\
	*value = *(type*)(rbuf->data + rbuf->off);		\
	rbuf->off += type_size;						\
	return 0;									\

typedef struct
{
	uint8_t* 	data;
    size_t 		size;
	int 		off;
	gchar		sbuf[256];		// 避免频繁分配空间
} ReadBuf;


static inline int rbuf_get_u8(ReadBuf* rbuf, uint8_t* value)
{
	rbuf_get(rbuf, value, uint8_t, 1)
}

static inline int rbuf_get_s16(ReadBuf* rbuf, int16_t* value)
{
	rbuf_get(rbuf, value, int16_t, 2)
}

static inline int rbuf_get_s32(ReadBuf* rbuf, int32_t* value)
{
	rbuf_get(rbuf, value, int32_t, 4)
}

static inline int rbuf_get_s64(ReadBuf* rbuf, int64_t* value)
{
	rbuf_get(rbuf, value, int64_t, 8)
}

static inline int rbuf_get_float(ReadBuf* rbuf, float* value)
{
	rbuf_get(rbuf, value, float, 4)
}

static inline int rbuf_get_double(ReadBuf* rbuf, double* value)
{
	rbuf_get(rbuf, value, double, 8)
}

static inline int rbuf_get_string(ReadBuf* rbuf, gchar** value, int dup)
{
	// 长度
	if (rbuf->off+4 > rbuf->size)
		return -1;
	int len = *(int32_t*)(rbuf->data + rbuf->off);
	rbuf->off += 4;

	// 字符串
	if (rbuf->off+len > rbuf->size)
		return -1;
	// 动态创建
	if (dup || len >= 256) {
		*value = g_strndup((gchar*)rbuf->data + rbuf->off, len);
	} else {
		// 复用
		*value = rbuf->sbuf;
		memcpy(rbuf->sbuf, rbuf->data + rbuf->off, len);
		rbuf->sbuf[len] = 0;
	}
	rbuf->off += len;
	return 0;
}


/** 反序列化map(map计数为1) */
ipc_map_t* ipc_map_unserial(uint8_t* bytes, int size)
{
	if (bytes == NULL || size == 0)
		return NULL;

	ipc_map_t* map = ipc_map_new();

	ReadBuf rbuf;
	rbuf.data = bytes;
	rbuf.size = size;
	rbuf.off = 0;

	gchar* key = NULL;
	uint8_t type;
	int array_size;

	while (rbuf.off < size) {
		// 键
		if (rbuf_get_string(&rbuf, &key, 0))
			goto fail;

		// 类型
		if (rbuf_get_u8(&rbuf, &type))
			goto fail;

		// 值
		switch (type)
		{
			case IPC_MAP_ITEM_TYPE_U8: {
				uint8_t value;
				if (rbuf_get_u8(&rbuf, &value))
					goto fail;
				ipc_map_set_u8(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_S16: {
				int16_t value;
				if (rbuf_get_s16(&rbuf, &value))
					goto fail;
				ipc_map_set_s16(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_S32: {
				int32_t value;
				if (rbuf_get_s32(&rbuf, &value))
					goto fail;
				ipc_map_set_s32(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_S64: {
				int64_t value;
				if (rbuf_get_s64(&rbuf, &value))
					goto fail;
				ipc_map_set_s64(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_FLOAT: {
				float value;
				if (rbuf_get_float(&rbuf, &value))
					goto fail;
				ipc_map_set_float(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_DOUBLE: {
				double value;
				if (rbuf_get_double(&rbuf, &value))
					goto fail;
				ipc_map_set_double(map, key, value);
				break;
			}

			case IPC_MAP_ITEM_TYPE_STRING: {
				gchar* value = NULL;
				if (rbuf_get_string(&rbuf, &value, 1))
					goto fail;
				ipc_map_set_string(map, key, value);
				if (value != rbuf.sbuf) {
					str_check_free(value);
				}
				break;
			}

			case IPC_MAP_ITEM_TYPE_U8_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size > size)
					goto fail;
				ipc_map_set_u8_array(map, key, ipc_u8_array_new2(rbuf.data+rbuf.off, array_size));
				rbuf.off += array_size;
				break;
			}

			case IPC_MAP_ITEM_TYPE_S16_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size*2 > size)
					goto fail;
				ipc_map_set_s16_array(map, key, ipc_s16_array_new2((int16_t*)(rbuf.data+rbuf.off), array_size));
				rbuf.off += array_size*2;
				break;
			}

			case IPC_MAP_ITEM_TYPE_S32_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size*4 > size)
					goto fail;
				ipc_map_set_s32_array(map, key, ipc_s32_array_new2((int32_t*)(rbuf.data+rbuf.off), array_size));
				rbuf.off += array_size*4;
				break;
			}

			case IPC_MAP_ITEM_TYPE_S64_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size*8 > size)
					goto fail;
				ipc_map_set_s64_array(map, key, ipc_s64_array_new2((int64_t*)(rbuf.data+rbuf.off), array_size));
				rbuf.off += array_size*8;
				break;
			}

			case IPC_MAP_ITEM_TYPE_FLOAT_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size*4 > size)
					goto fail;
				ipc_map_set_float_array(map, key, ipc_float_array_new2((float*)(rbuf.data+rbuf.off), array_size));
				rbuf.off += array_size*4;
				break;
			}

			case IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size) || rbuf.off + array_size*8 > size)
					goto fail;
				ipc_map_set_double_array(map, key, ipc_double_array_new2((double*)(rbuf.data+rbuf.off), array_size));
				rbuf.off += array_size*8;
				break;
			}

			case IPC_MAP_ITEM_TYPE_STRING_ARRAY: {
				if (rbuf_get_s32(&rbuf, &array_size))
					goto fail;
				ipc_string_array_t* array = ipc_string_array_new(array_size);
				gchar* value = NULL;
				for (int i = 0; i < array_size; i++) {
					if (rbuf_get_string(&rbuf, &value, 1)) {
						ipc_string_array_unref(array);
						goto fail;
					}
					array->value[i] = value;
				}
				ipc_map_set_string_array(map, key, array);
				break;
			}
		}

		// 释放key
		if (key != rbuf.sbuf) {
			str_check_free(key);
			key = NULL;
		}
	}
	return map;

fail:
	// 释放key
	if (key != rbuf.sbuf) {
		str_check_free(key);
	}
	ipc_map_unref(map);
	return NULL;
}

// 条目位置,获取条目,添加条目,删除条目 ----------------------------------------

/** 获取条目位置 */
static int ipc_map_get_item_pos(ipc_map_t* map, const gchar* key)
{
    int first = 0;
    int last = map->size;

    while (last > first) {
        int next = (last + first) >> 1;
        ipc_map_item_t* item = map->items[next];
        int cmp = strcmp(key, item->key);
        if (!cmp)
            return -next - 1;
        if (cmp < 0) {
            last = next;
            continue;
        }
        first = next + 1;
    }
    return first;
}

/** 获取条目 */
static ipc_map_item_t* ipc_map_get_item(ipc_map_t* map, const gchar* key)
{
	if (map != NULL && key != NULL) {
		int pos = ipc_map_get_item_pos(map, key);
		return pos < 0 ? map->items[-pos - 1] : NULL;
	}
	return NULL;
}

/** 创建IPC_MAP_ITEM_TYPE_U8类型的条目 */
static ipc_map_item_t* ipc_map_item_new(const gchar* key)
{
	ipc_map_item_t* item = (ipc_map_item_t*)malloc(sizeof(ipc_map_item_t));
	item->type = IPC_MAP_ITEM_TYPE_U8;
	item->key = str_check_dup(key);	// 复制key
	item->v.u8_value = 0;
	return item;
}

/** 获取或者创建以key为键的条目 */
static ipc_map_item_t* ipc_map_get_or_add_item(ipc_map_t* map, const gchar* key)
{
	int pos = ipc_map_get_item_pos(map, key);

	// 存在,返回
	if (pos < 0) {
		return map->items[-pos - 1];
	}

	// 空间满，重新分配
	if (map->size == map->capacity) {
		map->capacity = get_new_capcity_by_size(map->size);
		map->items = (ipc_map_item_t**) realloc(map->items, sizeof(ipc_map_item_t*) * map->capacity);
	}

	// 新建条目添加到pos
	ipc_map_item_t* item = ipc_map_item_new(key);
	map->size++;
	// 不添加在末端, 留出位置
	if (map->size > pos) {
		memmove(map->items + pos + 1, map->items + pos, sizeof(ipc_map_item_t*) * (map->size - pos - 1));
	}
	map->items[pos] = item;
	return item;
}

/** 删除以key为键的条目 */
void ipc_map_remove(ipc_map_t* map, const gchar* key)
{
	if (map == NULL || key == NULL)
		return;

	ipc_lock();

	int pos = ipc_map_get_item_pos(map, key);
	if (pos < 0) {
		pos = -pos - 1;
		// 释放条目空间
		ipc_map_item_free(map->items[pos]);
		map->items[pos] = NULL;
		map->size--;
		if (pos < map->size) {
			memmove(map->items + pos, map->items + pos + 1, sizeof(ipc_map_item_t*) * (map->size - pos));
		}
	}

	ipc_unlock();
}


// 注意!!!!
// 1. 设置或者获取字符串，函数内部都会g_str_dup
// 2. 设置或者获取数组，函数内部都会增加数组的引用计数
// 3. 所以对于数组的有效实践是
// 		1) 添加到map之后如果外面不需要了unref一下
// 		2) 从map取得之后，如果外面不需要了unref一下

// 查找(key对应的item类型不对，不会有返回值) ---------------------------------

uint8_t ipc_map_get_u8_3(ipc_map_t* map, const gchar* key, uint8_t default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_U8) {
		default_value = item->v.u8_value;
	}
	ipc_unlock();
	return default_value;
}


int16_t ipc_map_get_s16_3(ipc_map_t* map, const gchar* key, int16_t default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S16) {
		default_value = item->v.s16_value;
	}
	ipc_unlock();
	return default_value;
}


int32_t ipc_map_get_s32_3(ipc_map_t* map, const gchar* key, int32_t default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S32) {
		default_value = item->v.s32_value;
	}
	ipc_unlock();
	return default_value;
}


int64_t ipc_map_get_s64_3(ipc_map_t* map, const gchar* key, int64_t default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S64) {
		default_value = item->v.s64_value;
	}
	ipc_unlock();
	return default_value;
}


float ipc_map_get_float_3(ipc_map_t* map, const gchar* key, float default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_FLOAT) {
		default_value = item->v.float_value;
	}
	ipc_unlock();
	return default_value;
}


double ipc_map_get_double_3(ipc_map_t* map, const gchar* key, double default_value)
{
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_DOUBLE) {
		default_value = item->v.double_value;
	}
	ipc_unlock();
	return default_value;
}


const gchar* ipc_map_get_string_3(ipc_map_t* map, const gchar* key, const gchar* default_value)
{
	ipc_lock();
	
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_STRING) {
		const gchar* ret = item->v.string_value;
		ipc_unlock();
		return ret;
	}
	ipc_unlock();
	return default_value;
}


ipc_u8_array_t* ipc_map_get_u8_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_u8_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_U8_ARRAY) {
		ret = item->v.u8_array;
	}
	ipc_unlock();
	return ret;
}


ipc_s16_array_t* ipc_map_get_s16_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_s16_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S16_ARRAY) {
		ret = item->v.s16_array;
	}
	ipc_unlock();
	return ret;
}


ipc_s32_array_t* ipc_map_get_s32_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_s32_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S32_ARRAY) {
		ret = item->v.s32_array;
	}
	ipc_unlock();
	return ret;
}


ipc_s64_array_t* ipc_map_get_s64_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_s64_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_S64_ARRAY) {
		ret = item->v.s64_array;
	}
	ipc_unlock();
	return ret;
}


ipc_float_array_t* ipc_map_get_float_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_float_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_FLOAT_ARRAY) {
		ret = item->v.float_array;
	}
	ipc_unlock();
	return ret;
}


ipc_double_array_t* ipc_map_get_double_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_double_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY) {
		ret = item->v.double_array;
	}
	ipc_unlock();
	return ret;
}

ipc_string_array_t* ipc_map_get_string_array(ipc_map_t* map, const gchar* key)
{
	ipc_lock();
	ipc_string_array_t* ret = NULL;
	ipc_map_item_t* item = ipc_map_get_item(map, key);
	if (item != NULL && item->type == IPC_MAP_ITEM_TYPE_STRING_ARRAY) {
		ret = item->v.string_array;
	}
	ipc_unlock();
	return ret;
}


// 基本类型查找(默认值0) --------------------------------------------------------------

uint8_t ipc_map_get_u8(ipc_map_t* map, const gchar* key) 	{return ipc_map_get_u8_3(map, key, 0);}
int16_t ipc_map_get_s16(ipc_map_t* map, const gchar* key) 	{return ipc_map_get_s16_3(map, key, 0);}
int32_t ipc_map_get_s32(ipc_map_t* map, const gchar* key)	{return ipc_map_get_s32_3(map, key, 0);}
int64_t ipc_map_get_s64(ipc_map_t* map, const gchar* key)	{return ipc_map_get_s64_3(map, key, 0);}
float ipc_map_get_float(ipc_map_t* map, const gchar* key)	{return ipc_map_get_float_3(map, key, 0);}
double ipc_map_get_double(ipc_map_t* map, const gchar* key)	{return ipc_map_get_double_3(map, key, 0);}
const gchar* ipc_map_get_string(ipc_map_t* map, const gchar* key)	{return ipc_map_get_string_3(map, key, NULL);}



// 设置相关 ---------------------------------------------------------------------------


void ipc_map_set_u8(ipc_map_t* map, const gchar* key, uint8_t value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_U8;
	item->v.u8_value = value;
	ipc_unlock();
}


void ipc_map_set_s16(ipc_map_t* map, const gchar* key, int16_t value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_S16;
	item->v.s16_value = value;
	ipc_unlock();
}


void ipc_map_set_s32(ipc_map_t* map, const gchar* key, int32_t value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_S32;
	item->v.s32_value = value;
	ipc_unlock();
}


void ipc_map_set_s64(ipc_map_t* map, const gchar* key, int64_t value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_S64;
	item->v.s64_value = value;
	ipc_unlock();
}


void ipc_map_set_float(ipc_map_t* map, const gchar* key, float value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_FLOAT;
	item->v.float_value = value;
	ipc_unlock();
}


void ipc_map_set_double(ipc_map_t* map, const gchar* key, double value)
{
	if (map == NULL || key == NULL)
		return;
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_DOUBLE;
	item->v.double_value = value;
	ipc_unlock();
}


void ipc_map_set_string(ipc_map_t* map, const gchar* key, const gchar* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL || *value == 0) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	ipc_map_item_free_value(item);
	item->type = IPC_MAP_ITEM_TYPE_STRING;
	item->v.string_value = str_check_dup(value);
	ipc_unlock();
}


void ipc_map_set_u8_array(ipc_map_t* map, const gchar* key, ipc_u8_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_U8_ARRAY || item->v.u8_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_U8_ARRAY;
		item->v.u8_array = value;
	}
	ipc_unlock();
}


void ipc_map_set_s16_array(ipc_map_t* map, const gchar* key, ipc_s16_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_S16_ARRAY || item->v.s16_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_S16_ARRAY;
		item->v.s16_array = value;
	}
	ipc_unlock();
}


void ipc_map_set_s32_array(ipc_map_t* map, const gchar* key, ipc_s32_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_S32_ARRAY || item->v.s32_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_S32_ARRAY;
		item->v.s32_array = value;
	}
	ipc_unlock();
}


void ipc_map_set_s64_array(ipc_map_t* map, const gchar* key, ipc_s64_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_S64_ARRAY || item->v.s64_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_S64_ARRAY;
		item->v.s64_array = value;
	}
	ipc_unlock();
}


void ipc_map_set_float_array(ipc_map_t* map, const gchar* key, ipc_float_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_FLOAT_ARRAY || item->v.float_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_FLOAT_ARRAY;
		item->v.float_array = value;
	}
	ipc_unlock();
}


void ipc_map_set_double_array(ipc_map_t* map, const gchar* key, ipc_double_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY || item->v.double_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_DOUBLE_ARRAY;
		item->v.double_array = value;
	}
	ipc_unlock();
}

void ipc_map_set_string_array(ipc_map_t* map, const gchar* key, ipc_string_array_t* value)
{
	if (map == NULL || key == NULL)
		return;
	// 删除
	if (value == NULL) {
		ipc_map_remove(map, key);
		return;
	}
	ipc_lock();
	ipc_map_item_t* item = ipc_map_get_or_add_item(map, key);
	if (item->type != IPC_MAP_ITEM_TYPE_STRING_ARRAY || item->v.string_array != value) {
		ipc_map_item_free_value(item);
		item->type = IPC_MAP_ITEM_TYPE_STRING_ARRAY;
		item->v.string_array = value;
	}
	ipc_unlock();
}

#if 0
int main()
{
	ipc_map_t* map = ipc_map_new();

	// 非数组设置与获取1 --------------------------------------------
	ipc_map_set_u8(map, "u8", 8);
	ipc_map_set_s16(map, "s16", 16);
	ipc_map_set_s32(map, "s32", 32);
	ipc_map_set_s64(map, "s64", 64);
	ipc_map_set_float(map, "float", 123);
	ipc_map_set_double(map, "double", 456);
	ipc_map_set_string(map, "string", "hello");

#if 1	// 序列化反序列化
	int size;
	uint8_t* bytes = ipc_map_serial(map, &size);
	ipc_map_unref(map);

	map = ipc_map_unserial(bytes, size);
	free(bytes);
#endif

	g_print("u8 = %d\n", ipc_map_get_u8(map, "u8"));
	g_print("s16 = %d\n", ipc_map_get_s16(map, "s16"));
	g_print("s32 = %d\n", ipc_map_get_s32(map, "s32"));
	g_print("s64 = %ld\n", ipc_map_get_s64(map, "s64"));
	g_print("float = %f\n", ipc_map_get_float(map, "float"));
	g_print("double = %f\n", ipc_map_get_double(map, "double"));
	g_print("string = %s\n", ipc_map_get_string(map, "string"));

	// 非数组设置与获取2 --------------------------------------------
	ipc_map_set_u8(map, "u8", 18);
	ipc_map_set_s16(map, "s16", 116);
	ipc_map_set_s32(map, "s32", 132);
	ipc_map_set_s64(map, "s64", 164);
	ipc_map_set_float(map, "float", 321);
	ipc_map_set_double(map, "double", 654);
	ipc_map_set_string(map, "string", "world");

	g_print("\n-----------------------------\n");
	g_print("u8 = %d\n", ipc_map_get_u8(map, "u8"));
	g_print("s16 = %d\n", ipc_map_get_s16(map, "s16"));
	g_print("s32 = %d\n", ipc_map_get_s32(map, "s32"));
	g_print("s64 = %ld\n", ipc_map_get_s64(map, "s64"));
	g_print("float = %f\n", ipc_map_get_float(map, "float"));
	g_print("double = %f\n", ipc_map_get_double(map, "double"));
	g_print("string = %s\n", ipc_map_get_string(map, "string"));

	// 获取现存的key --------------------------------------------
	ipc_string_array_t* keys = ipc_map_keys(map);
	if (keys != NULL) {
		g_print("\n-----------------------------\n");
		for (int i = 0; i < ipc_string_array_size(keys); i++)
			g_print("key = %s\n", ipc_string_array_get(keys, i));
	}
	if (ipc_string_array_unref(keys) == 0) {
		keys = NULL;
	}

	// 删除一些key, 再获取现存的key ----------------------------------------------
	ipc_map_remove(map, "s32");
	ipc_map_remove(map, "float");
	ipc_map_remove(map, "string");
	keys = ipc_map_keys(map);
	if (keys != NULL) {
		g_print("\n-----------------------------\n");
		for (int i = 0; i < ipc_string_array_size(keys); i++)
			g_print("key = %s\n", ipc_string_array_get(keys, i));
	}
	if (ipc_string_array_unref(keys) == 0) {
		keys = NULL;
	}

	// 删除一些key, 再获取现存的key ----------------------------------------------
	ipc_map_remove(map, "u8");
	ipc_map_remove(map, "s64");
	keys = ipc_map_keys(map);
	if (keys != NULL) {
		g_print("\n-----------------------------\n");
		for (int i = 0; i < ipc_string_array_size(keys); i++)
			g_print("key = %s\n", ipc_string_array_get(keys, i));
	}
	if (ipc_string_array_unref(keys) == 0) {
		keys = NULL;
	}
}
#endif

// (衍生函数)创建带id-value的map -------------------------------------------------------

ipc_map_t* ipc_map_new_with_id(const gchar* id)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_string(map, IPC_MAP_KEY_ID, id);
	return map;
}

ipc_map_t* ipc_map_new_id_u8(const gchar* id, uint8_t value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_u8(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s16(const gchar* id, int16_t value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s16(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s32(const gchar* id, int32_t value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s32(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s64(const gchar* id, int64_t value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s64(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_float(const gchar* id, float value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_float(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_double(const gchar* id, double value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_double(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_string(const gchar* id, const gchar* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_string(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_u8_array(const gchar* id, ipc_u8_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_u8_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s16_array(const gchar* id, ipc_s16_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s16_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s32_array(const gchar* id, ipc_s32_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s32_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_s64_array(const gchar* id, ipc_s64_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_s64_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_float_array(const gchar* id, ipc_float_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_float_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_double_array(const gchar* id, ipc_double_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_double_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_string_array(const gchar* id, ipc_string_array_t* value)
{
	ipc_map_t* map = ipc_map_new_with_id(id);
	ipc_map_set_string_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

// ---------------------------------------------------------------------------------------

ipc_map_t* ipc_map_new_u8(uint8_t value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_u8(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s16(int16_t value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s16(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s32(int32_t value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s32(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s64(int64_t value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s64(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_float(float value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_float(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_double(double value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_double(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_string(const gchar* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_string(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_u8_array(ipc_u8_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_u8_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s16_array(ipc_s16_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s16_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s32_array(ipc_s32_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s32_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_s64_array(ipc_s64_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_s64_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_float_array(ipc_float_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_float_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_double_array(ipc_double_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_double_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_string_array(ipc_string_array_t* value)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_string_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

// 键是IPC_MAP_KEY_OBSERVER (通常用于handle_update中进行server_update2) --------------------------

ipc_map_t* ipc_map_new_id_observer(const gchar* id, gint64 observer)
{
	ipc_map_t* map = ipc_map_new();
	ipc_map_set_string(map, IPC_MAP_KEY_ID, id);
	ipc_map_set_s64(map, IPC_MAP_KEY_OBSERVER, observer);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_u8(const gchar* id, gint64 observer, uint8_t value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_u8(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s16(const gchar* id, gint64 observer, int16_t value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s16(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s32(const gchar* id, gint64 observer, int32_t value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s32(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s64(const gchar* id, gint64 observer, int64_t value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s64(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_float(const gchar* id, gint64 observer, float value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_float(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_double(const gchar* id, gint64 observer, double value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_double(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_string(const gchar* id, gint64 observer, const gchar* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_string(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_u8_array(const gchar* id, gint64 observer, ipc_u8_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_u8_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s16_array(const gchar* id, gint64 observer, ipc_s16_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s16_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s32_array(const gchar* id, gint64 observer, ipc_s32_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s32_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_s64_array(const gchar* id, gint64 observer, ipc_s64_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_s64_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_float_array(const gchar* id, gint64 observer, ipc_float_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_float_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_double_array(const gchar* id, gint64 observer, ipc_double_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_double_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}

ipc_map_t* ipc_map_new_id_observer_string_array(const gchar* id, gint64 observer, ipc_string_array_t* value)
{
	ipc_map_t* map = ipc_map_new_id_observer(id, observer);
	ipc_map_set_string_array(map, IPC_MAP_KEY_VALUE, value);
	return map;
}


// (衍生函数)获取id或者value -------------------------------------------------------

const gchar* ipc_map_get_id(ipc_map_t* map)
{
	return ipc_map_get_string(map, IPC_MAP_KEY_ID);
}

const gchar* ipc_map_get_client(ipc_map_t* map)
{
	return ipc_map_get_string(map, IPC_MAP_KEY_CLIENT);
}

// (注意!!!, map不对取得的数组增加引用，因此不想随着map一起销毁，需要在取得之后主动添加引用,
// 就是说map销毁时会unref引用的数组)	
ipc_u8_array_t* ipc_map_get_u8_array_value(ipc_map_t* map)
{
	return ipc_map_get_u8_array(map, IPC_MAP_KEY_VALUE);
}

ipc_s16_array_t* ipc_map_get_s16_array_value(ipc_map_t* map)
{
	return ipc_map_get_s16_array(map, IPC_MAP_KEY_VALUE);
}

ipc_s32_array_t* ipc_map_get_s32_array_value(ipc_map_t* map)
{
	return ipc_map_get_s32_array(map, IPC_MAP_KEY_VALUE);
}

ipc_s64_array_t* ipc_map_get_s64_array_value(ipc_map_t* map)
{
	return ipc_map_get_s64_array(map, IPC_MAP_KEY_VALUE);
}

ipc_float_array_t* ipc_map_get_float_array_value(ipc_map_t* map)
{
	return ipc_map_get_float_array(map, IPC_MAP_KEY_VALUE);
}

ipc_double_array_t* ipc_map_get_double_array_value(ipc_map_t* map)
{
	return ipc_map_get_double_array(map, IPC_MAP_KEY_VALUE);
}

ipc_string_array_t* ipc_map_get_string_array_value(ipc_map_t* map)
{
	return ipc_map_get_string_array(map, IPC_MAP_KEY_VALUE);
}

// 基本类型查找(默认值0或者NULL) -------------------------------------------------
uint8_t ipc_map_get_u8_value(ipc_map_t* map)
{
	return ipc_map_get_u8(map, IPC_MAP_KEY_VALUE);
}

int16_t ipc_map_get_s16_value(ipc_map_t* map)
{
	return ipc_map_get_s16(map, IPC_MAP_KEY_VALUE);
}

int32_t ipc_map_get_s32_value(ipc_map_t* map)
{
	return ipc_map_get_s32(map, IPC_MAP_KEY_VALUE);
}

int64_t ipc_map_get_s64_value(ipc_map_t* map)
{
	return ipc_map_get_s64(map, IPC_MAP_KEY_VALUE);
}

float ipc_map_get_float_value(ipc_map_t* map)
{
	return ipc_map_get_float(map, IPC_MAP_KEY_VALUE);
}

double ipc_map_get_double_value(ipc_map_t* map)
{
	return ipc_map_get_double(map, IPC_MAP_KEY_VALUE);
}

// (注意!!!, 取得的gchar*由map所有，因此不想随着map一起销毁，需要在取得之后主动str_check_dup)
const gchar* ipc_map_get_string_value(ipc_map_t* map)
{
	return ipc_map_get_string(map, IPC_MAP_KEY_VALUE);
}

// gcc -g -Wall ipc_data.c -o ipc_data `pkg-config --libs --cflags glib-2.0 gio-2.0`

